#ifndef MAIN_H
#define MAIN_H

#include <iostream>
#include <cmath>
#include <stdlib.h>
#include <time.h>

#include "WorldStatusUpdate.pb.h"
#include "Commands.pb.h"
#include "ProtobufUtil.hh"

using namespace strategy_protocol;
using namespace protoutil;
using namespace std;

class TheStrategy {
		int N = 0, M = 0; //map size
		int MYTEAM;
		const int soldier_shoot_dist = 3;
		const int worker_shoot_dist = 2;
		const int boss_shoot_dist = 5;
		const int soldier_cost = 50;
		const int worker_cost = 20;
		const int soldier_strength = 4;
		const int worker_strength = 2;
		const unsigned int blockers_size = 16;
		string base_id;
		Position base_pos;
		string boss_id;
		Position boss_pos;
		bool boss_found = false;
        vector<string> the_brave_workers;
		Position explorer_tour;
		int min_x;
		int min_y;
		int max_x;
		int max_y;
        int translation_x = 0;
        int translation_y = 0;
		bool need_worker = true;
		vector<vector<char> > mymap;
		vector<vector<bool> > reachable_pos;
		vector<vector<bool> > discovered;
		vector<WorldStatusUpdateMessage_Mine> mines;

		vector<bool> soldier_has_target; // local info
		vector<bool> worker_has_target; // local info
		map<string,Position> his_mine; // id -> mine, global info

        bool block = false;

		vector<vector<Position> > forward_route;
		vector<vector<Position> > backward_route;

        vector<int> soldiers_target_limit;
        vector<Position> soldiers_target_pos;

		enum Task {MINE,BLOCK,INVADE,EXPLORE,ATTACK,MOVE,DEFEND};
		struct TaskProperty {
			Task task;
			Task subtask;
			Position target_pos;
			bool approx;
			int waiting;
			void set(Task _task,Position _target_pos,int _waiting)
			{
				waiting = _waiting;
				task = _task;
				target_pos = _target_pos;
			}
		};
		map<string,TaskProperty> soldiers_task;
		map<string,TaskProperty> workers_task;


		struct MoveProperty {
			Position source_pos;
			Position target_pos;
			void set(Position _source_pos,Position _target_pos)
			{
				source_pos = _source_pos;
				target_pos = _target_pos;
			};
		};

		map<string,MoveProperty> moves;


		bool invasion = false;
		int dead_blocker = -1;
		vector<string> invaders;
	public:
		TheStrategy() {}

		WorldStatusUpdateMessage world;
		CommandsMessage commands;

		/// ALGORITHMS.CPP
		Position nextstep(Position p,Position q,bool approx,bool considering_people);
		int real_distance(Position p,Position q,bool considering_people);
		vector<Position> route(Position p,Position q,vector<Position> forbidden_pos);
		void computing_all_reachable_positions_from_base();

		/// BASICS.CPP
		int distance(Position p, Position q);
		bool same_pos(Position p, Position q);
		void attackcmd(WorldStatusUpdateMessage_Soldier soldier, string enemy);
		void attackcmd(WorldStatusUpdateMessage_Worker worker, string enemy);
		void movecmd(WorldStatusUpdateMessage_Soldier soldier, Position pos);
		void movecmd(WorldStatusUpdateMessage_Worker worker, Position pos);
		void traincmd(CommandsMessage::ActorType myman);
		void mymap_building();
		void initialize_tick(int i);
		bool reachable(Position p,Position q,bool considering_people);
		bool forbidden(char ch);
		vector<Position> exists_free_space(Position target_pos);

		/// MYSTRATEGY.CPP
		void run();
		void what_should_i_do(WorldStatusUpdateMessage_Soldier soldier);
		void what_should_i_do(WorldStatusUpdateMessage_Worker worker,bool i_need_new_mine);
		void new_born();
		void boss_attack();
        void training();
        void the_brave_worker_story();
        bool soldiers_needed();
        bool soldiers_task_decision();

		/// MYSTRATEGY_MOVING.CPP
		void synchronized_moving();
		void best_routes_to_mines();
		void workers_on_the_best_routes();
		void workers_synchronized_moving();
		void soldiers_synchronized_moving();

		/// MYSTRATEGY_EXPLORING.CPP
		void random_undiscovered(bool workers,string id);
		// void random_tour(WorldStatusUpdateMessage_Soldier myman);
		// void random_tour_snail(WorldStatusUpdateMessage_Soldier myman);
		// void everybody_random_tour();

		/// MYSTRATEGY_ATTACK.CPP
		void attack_nearby_minions();
		void go_n_attack_boss(int j);
		void everybody_go_n_attack_boss();
		void defending_tour(WorldStatusUpdateMessage_Soldier myman,Position defending_pos);
		void go_n_block();
		void go_n_kill_boss();

		/// MYSTRATEGY_MINING.CPP
		void best_routes_to_mine(Position mine_position);
		void workers_to_mine();
		void worker_to_mine(WorldStatusUpdateMessage_Worker worker,Position mine_position);
};

#endif
